﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http.Routing;
using System.Web.Http.Dispatcher;
using System.Web.Http.Controllers;

namespace Flagwind.Web.Plugins
{
	public class PluginHttpControllerSelector : IHttpControllerSelector
	{
		#region 常量定义

		private const string ROOT_CONTROLLERS_PATH = "/Workspace/Controllers";

		#endregion

		#region 成员字段

		private Flagwind.Plugins.PluginContext _pluginContext;

		#endregion

		#region 构造方法

		public PluginHttpControllerSelector(Flagwind.Plugins.PluginContext pluginContext)
		{
			if(pluginContext == null)
				throw new ArgumentNullException(nameof(pluginContext));

			_pluginContext = pluginContext;
		}

		#endregion

		#region 公共方法

		public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
		{
			throw new NotImplementedException();
		}

		public HttpControllerDescriptor SelectController(HttpRequestMessage request)
		{
			var routeData = (IHttpRouteData)request.Properties[System.Web.Http.Hosting.HttpPropertyKeys.HttpRouteDataKey];

			if(routeData == null)
				return null;

			object item;

			//处理路由中action可能与args错位的问题。
			if(routeData.Values.TryGetValue("action", out item) && item != null && item is string)
			{
				foreach(var chr in (string)item)
				{
					//如果action包含非数字、字母及下划线字符则认为其与args错位了
					if(!Char.IsLetterOrDigit(chr) && chr != '_')
					{
						routeData.Values["args"] = item;
						routeData.Values["action"] = null;
						break;
					}
				}
			}

			string areaName, controllerPath;

			if(routeData.Route.DataTokens.TryGetValue("area", out item))
				areaName = (string)item;
			else
				areaName = VirtualPathUtility.GetArea(routeData.Route.RouteTemplate);

			if(string.IsNullOrWhiteSpace(areaName))
				controllerPath = Flagwind.Plugins.PluginPath.Combine(ROOT_CONTROLLERS_PATH, (string)routeData.Values["controller"]);
			else
				controllerPath = Flagwind.Plugins.PluginPath.Combine(ROOT_CONTROLLERS_PATH, areaName, (string)routeData.Values["controller"]);

			var node = _pluginContext.PluginTree.Find(controllerPath);

			if(node == null)
				return null;

			routeData.Values["area"] = areaName;
			routeData.Values["controller.path"] = controllerPath;

			return new PluginHttpControllerDescriptor(request.GetConfiguration(), node);
		}

		#endregion
	}
}
